#include "ioq.h"
#include "interrupt.h"
#include "global.h"
#include "debug.h"

void ioq_init(struct ioq* pioq){
    lock_init(&pioq->lock);
    pioq->producer = pioq->consumer = NULL;
    pioq->head = pioq->tail = 0;

}

static int32_t next_pos(int32_t pos){
    return (pos+1) % buf_size;
 } 

bool ioq_is_full(struct ioq* pioq){
    ASSERT(intr_get_status() == INTR_OFF);     // ?
    return next_pos(pioq->head) == pioq->tail;
}

bool ioq_is_empty(struct ioq* pioq){
    ASSERT(intr_get_status() == INTR_OFF);     // ?
    return pioq->head == pioq->tail;
}

static void ioq_wait(struct task_struct** waiter){
    ASSERT( waiter != NULL && *waiter == NULL );  // 这里的waiter指向的是等待赋值的ioq里面的成员
    *waiter = running_thread();
    thread_block(TASK_BLOCKED);
}

static void ioq_wakeup(struct task_struct** waiter){
    ASSERT(*waiter != NULL);
    thread_unblock(*waiter);
    *waiter = NULL;  // 从ioq中移除
}

char ioq_get_char(struct ioq* pioq){
    ASSERT(intr_get_status() == INTR_OFF);
    while(ioq_is_empty(pioq)){
        lock_acquire(&pioq->lock);
        ioq_wait(&pioq->consumer);
        lock_release(&pioq->lock);
    }
    char ch = pioq->buf[pioq->tail];
    pioq->tail = next_pos(pioq->tail);

    if(pioq->producer != NULL){ ioq_wakeup(&pioq->producer); }
    
    return ch;
}

void ioq_put_char(struct ioq* pioq, char ch){
    ASSERT(intr_get_status() == INTR_OFF);  // ?

    while(ioq_is_full(pioq)){
        lock_acquire(&pioq->lock);
        ioq_wait( &pioq->producer);
        lock_release(&pioq->lock);
    }
    pioq->buf[pioq->head] = ch;
    pioq->head = next_pos(pioq->head);

    if(pioq->consumer != NULL){ ioq_wakeup(&pioq->consumer); }
}






















